import { isUndefined, isNull, PagedList, PageParams } from "mmb";
import * as user_followpb from "../grpc-client/service/user_follow_pb";
import { jsTimestampToPb, pbTimestampToJs } from "./helper";

import {
  getBgsUserFollowOpSafely,
  getMetadata,
  getOptionsOfLight,
  wrapperGrpcError,
} from "../grpc-client/grpcAdapter";

import { UserFollow, UpsertUserFollowParams, UpdateUserFollowParams, UserFollowWithUserAndUserStat} from "./declareTypes"
import { getPub, makeTopicOfPub, wrapToMessage } from "../proxy/nsqProxy";

/****************************************************************************************/
/*                                   user_follow entity                                 */
/****************************************************************************************/

const topicOfUpsertUserFollow = "upsert-user_follow";

const userFollowPbToObject = (
  pb: user_followpb.UserFollowEntity
): UserFollow => {
  return {
    userFollowId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    followedUserId: `${pb.getFollowedUserId()}`,
    followed: pbTimestampToJs(pb.getFollowed()),
    remark: pb.getRemark(),
  };
};

/****************************************************************************************/
/*                                   user_follow cmd                                    */
/****************************************************************************************/

export const upsertUserFollowMq = async ({
  userId,
  followedUserId,
  followed,
}: UpsertUserFollowParams): Promise<boolean> => {
  return new Promise((resolve, reject) => {
    const topic = makeTopicOfPub(topicOfUpsertUserFollow)
    const msg = wrapToMessage({
      userId: Number(userId),
      followedUserId: Number(followedUserId),
      followed,
    })
    // console.log('publish upsertUserFollowMq =>', topic ,JSON.stringify(msg))
    getPub().publish(
      topic,
      msg,
      (err) => {
        if (err) {
          // console.log("upsertUserFollowMq err", err);
          reject(false);
        }
        // console.log("upsertUserFollowMq success");
        resolve(true);
      }
    );
  });
};

export const upsertUserFollow = async ({
  userId,
  followedUserId,
  followed,
}: UpsertUserFollowParams): Promise<UserFollow> => {
  const cl = getBgsUserFollowOpSafely();
  const req = new user_followpb.UpsertUserFollowRequest();
  req.setUserId(Number(userId));
  req.setFollowedUserId(Number(followedUserId));
  req.setFollowed(jsTimestampToPb(followed));

  return new Promise((resolve, reject) => {
    cl.upsertUserFollow(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      const opRet = res.getOpRet()!;
      if (!opRet.getSuccess()) {
        reject(wrapperGrpcError(opRet.getMsg()));
        return;
      }
      resolve(userFollowPbToObject(res.getUserFollow()!));
    });
  });
};

export const updateUserFollow = async ({
  userFollowId,
  remark,
}: UpdateUserFollowParams): Promise<UserFollow> => {
  const cl = getBgsUserFollowOpSafely();
  const req = new user_followpb.UpdateUserFollowRequest();

  req.setId(Number(userFollowId));
  if (!isUndefined(remark)) {
    req.setRemark(remark);
  }

  return new Promise((resolve, reject) => {
    cl.updateUserFollow(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      const opRet = res.getOpRet()!;
      if (!opRet.getSuccess()) {
        reject(wrapperGrpcError(opRet.getMsg()));
        return;
      }
      resolve(userFollowPbToObject(res.getUserFollow()!));
    });
  });
};

/****************************************************************************************/
/*                                   user_follow query                                  */
/****************************************************************************************/

export const getUserFollow = async (userFollowId: string): Promise<UserFollow> => {
  const cl = getBgsUserFollowOpSafely();
  const req = new user_followpb.GetUserFollowRequest();

  req.setId(Number(userFollowId));

  return new Promise((resolve, reject) => {
    cl.getUserFollow(req, getMetadata(), getOptionsOfLight(), (err, res) => {
      if (!isNull(err)) {
        reject(wrapperGrpcError(err.details));
        return;
      }
      const opRet = res.getOpRet()!;
      if (!opRet.getSuccess()) {
        reject(wrapperGrpcError(opRet.getMsg()));
        return;
      }
      resolve(userFollowPbToObject(res.getUserFollow()!));
    });
  });
};

/****************************************************************************************/
/*                                   user_follow joins entity                           */
/****************************************************************************************/

const userFollowWithUserAndUserStatPbToObject = (
  pb: user_followpb.UserFollowWithUserAndUserStatEntity
): UserFollowWithUserAndUserStat => {
  return {
    // user_follow
    userFollowId: `${pb.getId()}`,
    userId: `${pb.getUserId()}`,
    followedUserId: `${pb.getFollowedUserId()}`,
    followed: pbTimestampToJs(pb.getFollowed()),
    remark: pb.getRemark(),

    // user
    followedUserName: pb.getFollowedUserName(),
    followedUserPic: pb.getFollowedUserPic(),

    // user_stat
    fansCount: pb.getFansCount(),
    followUserCount: pb.getFollowUserCount(),
    followBrandCount: pb.getFollowBrandCount(),
    endorseBrandCount: pb.getEndorseBrandCount(),
    endorseActivityCount: pb.getEndorseActivityCount(),
    involveActivityCount: pb.getInvolveActivityCount(),
    orderCount: pb.getOrderCount(),
    viewCount: pb.getViewCount(),
    payAmount: pb.getPayAmount(),
  };
};

export const listUserFollowWithUserAndUserStats = async (
  userId: string,
  pager: PageParams
): Promise<PagedList<UserFollowWithUserAndUserStat>> => {
  const cl = getBgsUserFollowOpSafely();
  const req = new user_followpb.ListUserFollowWithUserAndUserStatsRequest();

  req.setLimit(pager.limit);
  req.setOffset(pager.offset);
  req.setUserId(Number(userId));

  return new Promise((resolve, reject) => {
    cl.listUserFollowWithUserAndUserStats(
      req,
      getMetadata(),
      getOptionsOfLight(),
      (err, res) => {
        if (!isNull(err)) {
          reject(wrapperGrpcError(err.details));
          return;
        }
        const opRet = res.getOpRet()!;
        if (!opRet.getSuccess()) {
          reject(wrapperGrpcError(opRet.getMsg()));
          return;
        }
        const ret: PagedList<UserFollowWithUserAndUserStat> = {
          total: 0,
          items: [],
        };
        ret.total = res.getTotal();
        ret.items = res
          .getUserFollowWithUserAndUserStatsList()
          .map((u) => userFollowWithUserAndUserStatPbToObject(u));
        resolve(ret);
      }
    );
  });
};
